#region File Description
/****************************************************************************
*                                                                           *
* Screen Manager.                                                           *
*                                                                           *
* Copyright (c) Ionescu Marius. All rights reserved(2010).                  *
*                                                                           *
****************************************************************************/
#endregion

#region Using Statements
using System;
using System.Diagnostics;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
#endregion

namespace XNA_FRAMEWORK
{
	public class XNAScreenMgr : DrawableGameComponent
	{
		#region Fields

		List<XNAGameScreen> screens = new List<XNAGameScreen>();
		List<XNAGameScreen> screensToUpdate = new List<XNAGameScreen>();
		XNAInput input = new XNAInput();

		SpriteBatch spriteBatch;
		SpriteFont font;
		Texture2D blankTexture;

		bool isInitialized;
		bool traceEnabled;

		#endregion

		#region Properties

		public SpriteBatch SpriteBatch
		{
			get { return spriteBatch; }
		}

		public SpriteFont Font
		{
			get { return font; }
		}

		public bool TraceEnabled
		{
			get { return traceEnabled; }
			set { traceEnabled = value; }
		}

		#endregion

		#region Initialization

		public XNAScreenMgr(Game game)
			: base(game)
		{
		}

		public override void Initialize()
		{
			base.Initialize();
			isInitialized = true;
		}

		protected override void LoadContent()
		{
			ContentManager content = Game.Content;

			spriteBatch = new SpriteBatch(GraphicsDevice);
			font = content.Load<SpriteFont>("menufont");
			blankTexture = content.Load<Texture2D>("blank");

			foreach (XNAGameScreen screen in screens)
			{
				screen.LoadContent();
			}
		}

		protected override void UnloadContent()
		{
			foreach (XNAGameScreen screen in screens)
			{
				screen.UnloadContent();
			}
		}


		#endregion

		#region Update and Draw

		public override void Update(GameTime gameTime)
		{
			input.Update();

			screensToUpdate.Clear();

			foreach (XNAGameScreen screen in screens)
				screensToUpdate.Add(screen);

			bool otherScreenHasFocus = !Game.IsActive;
			bool coveredByOtherScreen = false;

			while (screensToUpdate.Count > 0)
			{
				XNAGameScreen screen = screensToUpdate[screensToUpdate.Count - 1];

				screensToUpdate.RemoveAt(screensToUpdate.Count - 1);

				//Update from xnaGameScreen
				screen.Update(gameTime, otherScreenHasFocus, coveredByOtherScreen);

				if (screen.ScreenState == ScreenState.TransitionOn ||
					screen.ScreenState == ScreenState.Active)
				{
					if (!otherScreenHasFocus)
					{
						screen.HandleInput(input);

						otherScreenHasFocus = true;
					}

					if (!screen.IsPopup)
						coveredByOtherScreen = true;
				}
			}

			if (traceEnabled)
				TraceScreens();
		}

		void TraceScreens()
		{
			List<string> screenNames = new List<string>();

			foreach (XNAGameScreen screen in screens)
				screenNames.Add(screen.GetType().Name);

			Trace.WriteLine(string.Join(", ", screenNames.ToArray()));
		}

		public override void Draw(GameTime gameTime)
		{
			foreach (XNAGameScreen screen in screens)
			{
				if (screen.ScreenState == ScreenState.Hidden)
					continue;

				screen.Draw(gameTime);
			}
		}


		#endregion

		#region Public Methods

		public void AddScreen(XNAGameScreen screen, PlayerIndex? controllingPlayer)
		{
			screen.ControllingPlayer = controllingPlayer;
			screen.ScreenManager = this;
			screen.IsExiting = false;

			if (isInitialized)
			{
				screen.LoadContent();
			}

			screens.Add(screen);
		}

		public void RemoveScreen(XNAGameScreen screen)
		{
			if (isInitialized)
			{
				screen.UnloadContent();
			}

			screens.Remove(screen);
			screensToUpdate.Remove(screen);
		}

		public XNAGameScreen[] GetScreens()
		{
			return screens.ToArray();
		}

		public void FadeBackBufferToBlack(int alpha)
		{
			Viewport viewport = GraphicsDevice.Viewport;

			spriteBatch.Begin();

			spriteBatch.Draw(blankTexture, 
							 new Rectangle(0, 0, viewport.Width, viewport.Height),
							 new Color(0, 0, 0, (byte)alpha));

			spriteBatch.End();
		}
		#endregion
	}
}
